import { CrudService } from "@/shared/crud.service";
import { Inject, Injectable } from "@nestjs/common";
import { InjectDataSource } from "@nestjs/typeorm";
import { Brackets, DataSource } from "typeorm";
import { ContractCntrCreateDto, ContractCntrSumCreateDto, ContractCntrSumUpdateDto, ContractCreateDto, ContractFeedetCreateDto, ContractFeedetsUpdateDto, ContractTransCreateDto, ContractTransUpdateDto, ContractUpdateDto } from "./transport.dto";
import { DeleteDto, ResponseJson, SqlQueryDto } from "@/common/type/app.dto";
import { Contract, ContractCntr, ContractCntrSum, ContractTrans } from "./transport.entity";
import { plainToInstance } from "class-transformer";
import { validate } from "class-validator";
import { omit } from 'lodash';
import { ResponseCode } from "@/common/type/enum";
import { FeeDet } from "@/business/entities/business.entity";

@Injectable()
export class TransportService {
    constructor(
        @InjectDataSource() private datasource: DataSource,
        private crud: CrudService,
    ) { }

    async queryContractHeader(
        query: SqlQueryDto,
    ): Promise<ResponseJson<Contract[], number>> {
        return await this.crud.query<Contract>(Contract, query);
    }
    async queryContract(contract_id: number): Promise<ResponseJson<Contract, null>> {
        const contract = await this.datasource.manager.createQueryBuilder<Contract>(Contract, 'contract')
            .leftJoinAndSelect('contract.cntrsum', 'contract_cntr_sum')
            .leftJoinAndSelect('contract.trans', 'contract_trans')
            .leftJoinAndSelect('contract.feedets', 'fee_det')
            .where('contract.id = :contract_id', { contract_id: contract_id })
            .orderBy('contract_trans.seq', 'ASC')
            .getOne();
        return {
            code: ResponseCode.SuccessNoMsg,
            obj: contract,
        }
    }
    async deleteContract(dto: DeleteDto): Promise<ResponseJson> {
        // TODO:: 删除委托时判断委托费用是否已核销
        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const checkCount = await queryRunner.manager.createQueryBuilder<FeeDet>(FeeDet, 'fee_det')
                .select('count(*) as count')
                .where('contract_id in (:...ids)', { ids: dto.ids })
                .andWhere(
                    new Brackets((qb) => {
                        qb.where("audit_id = 'Y'").orWhere("invoice_audit_id = 'Y'")
                    }),
                )
                .getRawOne();
            // console.log(checkCount);
            
            if (parseInt(checkCount.count) > 0) {
                throw new Error('委托费用已核销，不允许删除');
            }
            await queryRunner.manager.createQueryBuilder()
                .delete()
                .from(Contract)
                .where('id in (:...ids)', { ids: dto.ids })
                .execute();
            await queryRunner.commitTransaction();
            return {
                code: ResponseCode.SuccessWithInfo,
                msg: ['删除成功']
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async queryContractTrans(query: SqlQueryDto): Promise<ResponseJson<ContractTrans[], number>> {
        return this.crud.query<ContractTrans>(ContractTrans, query);
    }
    async createContractHeader(dto: ContractCreateDto): Promise<ResponseJson<Contract, null>> {

        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const errors = await validate(plainToInstance(Contract, dto));
            if (errors.length > 0) {
                throw new Error(Object.values(errors[0].constraints).join('   '));
            }
            const r = await queryRunner.manager.createQueryBuilder()
                .insert()
                .into(Contract)
                .values(omit(dto, ['cntrsum', 'trans']))
                .execute();
            await queryRunner.commitTransaction();
            const contract = await queryRunner.manager.createQueryBuilder<Contract>(Contract, 'contract')
                .where('contract.id = :id', { id: r.identifiers[0].id })
                .getOne();

            return {
                code: ResponseCode.SuccessWithInfo,
                obj: contract,
                msg: ['委托头创建成功']
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async updateContractHeader(dto: ContractUpdateDto): Promise<ResponseJson<Contract, null>> {
        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const updateContractResult = await queryRunner.manager
                .createQueryBuilder()
                .update(Contract)
                .set(omit(dto, ['id']))
                .where('id = :id', { id: dto.id })
                .execute();
            if (updateContractResult.affected != 1) {
                throw new Error(`委托修改失败`);
            }
            await queryRunner.manager.createQueryBuilder()
                .update(FeeDet)
                .set({ bill_no: dto.bill_no })
                .where('contract_id = :contract_id', { contract_id: dto.id })
                .execute();
            if (updateContractResult.affected != 1) {
                throw new Error(`委托修改失败`);
            }
            await queryRunner.commitTransaction();
            const contract = await queryRunner.manager.createQueryBuilder<Contract>(Contract, 'contract')
                .where('contract.id = :id', { id: dto.id })
                .getOne();

            return {
                code: ResponseCode.SuccessWithInfo,
                msg: ['修改成功'],
                obj: contract,
            };
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async queryContractCntrSum(query: SqlQueryDto): Promise<ResponseJson<ContractCntrSum[], number>> {
        return await this.crud.query<ContractCntrSum>(ContractCntrSum, query);
    }
    async createContractCntrSum(dto: ContractCntrSumCreateDto): Promise<ResponseJson<ContractCntrSum, null>> {

        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const errors = await validate(plainToInstance(ContractCntrSum, dto));
            if (errors.length > 0) {
                throw new Error(Object.values(errors[0].constraints).join('   '));
            }
            const r = await queryRunner.manager.createQueryBuilder()
                .insert()
                .into(ContractCntrSum)
                .values(dto)
                .execute();
            await queryRunner.commitTransaction();
            const contractcntrsum = await queryRunner.manager.createQueryBuilder<ContractCntrSum>(ContractCntrSum, 'contract_cntr_sum')
                .where('contract_cntr_sum.id = :id', { id: r.identifiers[0].id })
                .getOne();

            return {
                code: ResponseCode.SuccessWithInfo,
                obj: contractcntrsum,
                msg: ['增加成功']
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async updateContractCntrSum(
        dto: ContractCntrSumUpdateDto,
    ): Promise<ResponseJson<null, null>> {
        return await this.crud.update<ContractCntrSum>(ContractCntrSum, dto);
    }
    async deleteContractSum(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<ContractCntrSum>(ContractCntrSum, dto);
    }
    async createContractCntrs(dto: ContractCntrCreateDto): Promise<ResponseJson<ContractCntr[], null>> {
        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            for (let index = 0; index < dto.cntrs.length; index++) {
                const element = dto.cntrs[index];
                /* const errors = await validate(plainToInstance(ContractCntr, element));
                if (errors.length > 0) {
                    throw new Error(Object.values(errors[0].constraints).join('   '));
                } */
                const r = await queryRunner.manager.createQueryBuilder()
                    .insert()
                    .into(ContractCntr)
                    .values({
                        contract_cntr_sum_id: dto.contract_cntr_sum_id,
                        cntr: element
                    })
                    .execute();
            }
            await queryRunner.commitTransaction();
            const r = await queryRunner.manager.createQueryBuilder<ContractCntr>(ContractCntr, 'contract_cntr')
                .where('contract_cntr.contract_cntr_sum_id = :contract_cntr_sum_id', { contract_cntr_sum_id: dto.contract_cntr_sum_id })
                .getMany();
            return {
                code: ResponseCode.SuccessWithInfo,
                msg: ['保存成功'],
                obj: r
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async deleteContractCntrs(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<ContractCntr>(ContractCntr, dto);
    }
    async queryContractCntrs(query: SqlQueryDto): Promise<ResponseJson<ContractCntr[], number>> {
        return await this.crud.query<ContractCntr>(ContractCntr, query);
    }
    async createContractTrans(dto: ContractTransCreateDto): Promise<ResponseJson<ContractTrans, null>> {

        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const lastSeq = await queryRunner.manager.createQueryBuilder<ContractTrans>(ContractTrans, 'contract_trans')
                .select('max(seq)', 'seq')
                .where('contract_trans.contract_id = :contract_id', { contract_id: dto.contract_id })
                .getRawOne();
            dto.seq = lastSeq.seq + 1;
            const errors = await validate(plainToInstance(ContractTrans, dto));
            if (errors.length > 0) {
                throw new Error(Object.values(errors[0].constraints).join('   '));
            }
            const r = await queryRunner.manager.createQueryBuilder()
                .insert()
                .into(ContractTrans)
                .values(dto)
                .execute();
            await queryRunner.commitTransaction();
            const trans = await queryRunner.manager.createQueryBuilder<ContractTrans>(ContractTrans, 'contract_trans')
                .where('contract_trans.id = :id', { id: r.identifiers[0].id })
                .getOne();

            return {
                code: ResponseCode.SuccessWithInfo,
                obj: trans,
                msg: ['增加成功']
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async updateContractTrans(
        dto: ContractTransUpdateDto,
    ): Promise<ResponseJson<null, null>> {
        return await this.crud.update<ContractTrans>(ContractTrans, dto);
    }
    async deleteContractTrans(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<ContractTrans>(ContractTrans, dto);
    }
    async createContractFeedet(
        dto: ContractFeedetCreateDto
    ): Promise<ResponseJson<FeeDet, null>> {
        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const errors = await validate(plainToInstance(FeeDet, dto));
            if (errors.length > 0) {
                throw new Error(Object.values(errors[0].constraints).join('   '));
            }
            const r = await queryRunner.manager.createQueryBuilder()
                .insert()
                .into(FeeDet)
                .values(dto)
                .execute();
            await queryRunner.commitTransaction();
            const feedet = await queryRunner.manager.createQueryBuilder<FeeDet>(FeeDet, 'fee_det')
                .where('fee_det.id = :id', { id: r.identifiers[0].id })
                .getOne();
            return {
                code: ResponseCode.SuccessWithInfo,
                msg: ['增加成功'],
                obj: feedet
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async updateContractFeedet(
        dto: ContractFeedetsUpdateDto
    ): Promise<ResponseJson<null, null>> {
        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            await queryRunner.manager.createQueryBuilder()
                .update(FeeDet)
                .set(omit(dto, ['id, contract_id']))
                .where('id = :id', { id: dto.id })
                .execute();
            await queryRunner.commitTransaction();
            return {
                code: ResponseCode.SuccessWithInfo,
                msg: ['修改成功']
            }
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async deleteContractFeedets(dto: DeleteDto): Promise<ResponseJson> {
        return await this.crud.delete<FeeDet>(FeeDet, dto);
    }
}